package com.tf_cut.backend.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lianlianpay.security.utils.LianLianPaySecurity;
import com.lianpay.api.util.TraderRSAUtil;
import com.tf_cut.backend.agent.vo.AgentCashOrderVo;
import com.tf_cut.backend.bean.*;
import com.tf_cut.backend.mapper.GrantDetailMapper;
import com.tf_cut.backend.platform.vo.GrantDetailVo;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class LLPayUtil {

    @Autowired
    private GrantDetailMapper grantDetailMapper;

    private final Logger logger = LoggerFactory.getLogger(LLPayUtil.class);
    /** 商户号（商户需要替换自己的商户号）. */
    private static final String OID_PARTNER = "202106290002729004";
    /** 商户私钥  */
    private static final String BUSINESS_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDH8cKCFBmeWME4iYy/rX1j9PudJ+bhxYS79lpZlY8G8DpXyzQ95IFGJo8azSkXibHHCJAgfiWp41/ZDC+uUSZfCJnRBOyPLrSeXyu5BDYJJPbBX8xt2yyotFWMvoRdqoKFHJInQ6wx0xh09gE/jbsJE20sCxzvCEKKdoKEY2T8tfvz7q1AS3koL0lrRMKr90gS3DsGAD2LSgED5adabs8cBFJQeZkpVLkX8kBsxX1G6ghQLa0df7Hh/mx0Y3g5TIYiiZrCqAaIERvifWxBczKx6/Si2yXqLxgjHHuHd1gtiG9BaH2GOUJoH2wtGATmjy1+uHS47VgApXr/UKWMDGg/AgMBAAECggEAWbUiq/IQvHbd2lv8hlN0mtBjw9MPR+Sy9RJG30K29Un7I0DMo6hOSAcs1b2O3jytQruYzrtKcrrNWjiZfAB00tatDJbE/EjcSOIyX8R/6gJno8MzmWZo1xhx+b/Q66WBAfAbsvot2/z2UCO/05/ndt78cHJb/PMbx7v8OyHNQYQo+XisJ5jIUBwHo4KOINIGEnsu4PoWAEqfQG4bUQ6p6ytma/xna/IgUG8/hH2CSLExZIA4L05Nx73Rhlo2hFNClB9XZYbleO2Yw1HxfgAzLu8Dj9UDUjoM357YAqDhWiZYfrHEpOOaPoZ4DN2X3XWMbXdjQQ+cotpHDeC6owChQQKBgQD62nGgQT9q7VO0uNAHqjilJTQDEf0F8fEYmvGPfdbYR4viwKHY7JGwEQ6UZg4D0EPFl/wiZARR1aW4rnMDT4w2y/vfT/B4871IUa5nJPKCcVGpz2dQ8PaRTI20P+KpbxIA088e7pHcextMQbuYQch/LOlDfToqR2P2+Fes/ZPjCQKBgQDMC+1ZDVoia7bpgB1OFDxLngA+rEyRZHorfdY3JFnhOO395dYeinpsJuXDDEegaehx9mmAAKSZSHVRSTuIQPkMuQ6xsIMCsrP/t01BFK/msRGmvV5IUjjZFKdMcDbLRja/dREasejyW3m0+hzTxPE4jKF155J2hYzKjAG1IyVbBwKBgHA9CvgEGabzFy/WPSYg0IV7tuDkzIw7a39x3EEysc1Ffd5wCDpx5uGbUCWv3/du2NPxI9wTWidva13NmCJUFk1ySXjqYJMNo5RXD6yQyHz6zOoopXZ+yiPK1+BdcUIUMz7xhku1vMekwVsGUjRWwqm8Y4ZR4pOGK8EV7sy1DNVZAoGBALx/fDlbQ1wvA9/8EZZyzSzR/snnJCjgmJga/M0eEMYmcH2wWLkIFoZY/MLOUlEX5bt59wZgEa7lKDP6ojuCQlEFmFSAitbwPabLMFwh/0nvZC4UHMhU5N1t3guYUpZA/Ays2is+FcPmy61rrTvZYTpreDFSx5QkVec7pcwvdq/7AoGAaqs25d6+zCM0bfe1BtZD4CxuNDGyGrmtzr58G8OoDI4nRfm40NqtmWRK6ENRg1NDnYgizFWEb2Iri4LkcyhYSGYvrFzIurmSaZSo+mbrY6bm7piQjhpC27JYKs7dTSLbJBUPiUBvxtUwFH99d7Lf8RoNmjkPzDItqYsUnMz+u90=";
    /** 实时付款api版本. */
    private static final String API_VERSION = "1.1";
    /** 实时付款签名方式. */
    private static final String SIGN_TYPE = "RSA";
    /** 连连银通公钥（不需替换，这是连连公钥，用于报文加密和连连返回响应报文时验签，不是商户生成的公钥. */
    private static final String PUBLIC_KEY_ONLINE = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCSS/DiwdCf/aZsxxcacDnooGph3d2JOj5GXWi+q3gznZauZjkNP8SKl3J2liP0O6rU/Y/29+IUe+GTMhMOFJuZm1htAtKiu5ekW0GlBMWxf4FPkYlQkPE0FtaoMP3gYfh+OwI+fIRrpW3ySn3mScnc6Z700nU/VYrRkfcSCbSnRwIDAQAB";
    //发放
    public void pay(GrantDetailVo detail) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

        PaymentRequestBean paymentRequestBean = new PaymentRequestBean();
        paymentRequestBean.setNo_order(detail.getId());
        paymentRequestBean.setDt_order(sdf.format(new Date()));
        paymentRequestBean.setMoney_order(detail.getPayAmount().toPlainString());
        paymentRequestBean.setCard_no(detail.getPayeeAccount());
        paymentRequestBean.setAcct_name(detail.getPayeeName());
       paymentRequestBean.setRisk_item("{'second_merch_name' : '"+detail.getSellerCompanyName() +"'}");
        paymentRequestBean.setBank_name(detail.getPayeeAccountBankName());
        paymentRequestBean.setInfo_order("代付");
        paymentRequestBean.setFlag_card("0");
        paymentRequestBean.setMemo("代付");
        // 填写商户自己的接收付款结果回调异步通知
        paymentRequestBean.setNotify_url("test");
        paymentRequestBean.setOid_partner(OID_PARTNER);
        paymentRequestBean.setPlatform("https://admin.xydtax.com");
        paymentRequestBean.setApi_version(API_VERSION);
        paymentRequestBean.setSign_type(SIGN_TYPE);
        // 用商户自己的私钥加签
        paymentRequestBean.setSign(SignUtil.genRSASign(JSON.parseObject(JSON.toJSONString(paymentRequestBean)),BUSINESS_PRIVATE_KEY));

        String jsonStr = JSON.toJSONString(paymentRequestBean);
        System.out.print("实时付款接口请求报文：" + jsonStr);
        logger.info("实时付款请求报文：" + jsonStr);

        String encryptStr = LianLianPaySecurity.encrypt(jsonStr, PUBLIC_KEY_ONLINE);

        if (StringUtils.isEmpty(encryptStr)) {
            // 加密异常
            logger.error("加密异常:");
            throw new Exception("加密异常");
        }

        JSONObject json = new JSONObject();
        json.put("oid_partner", OID_PARTNER);
        json.put("pay_load", encryptStr);

        String response = HttpUtil.doPost("https://instantpay.lianlianpay.com/paymentapi/payment.htm", json, "UTF-8");
        System.out.print("付款接口请求报文：" + json);
        System.out.print("付款接口返回响应报文：" + response);
        logger.info("付款接口返回响应报文：" + response);
        if (StringUtils.isEmpty(response)) {
            // 出现异常时调用订单查询，明确订单状态，不能私自设置订单为失败状态，以免造成这笔订单在连连付款成功了，而商户设置为失败
            detail.setPaymentStatus("P");
            detail.setPaymentMsg("出现异常");
            QueryPaymentQueue.set(detail);
        } else {
            PaymentResponseBean paymentResponseBean = JSONObject.parseObject(response, PaymentResponseBean.class);

            // 对返回0000时验证签名
            if (paymentResponseBean.getRet_code().equals("0000")) {
                // 先对结果验签
                boolean signCheck = TraderRSAUtil.checksign(PUBLIC_KEY_ONLINE,
                        SignUtil.genSignData(JSONObject.parseObject(response)), paymentResponseBean.getSign());
                if (!signCheck) {
                    // 传送数据被篡改，可抛出异常，再人为介入检查原因
                    logger.error("返回结果验签异常,可能数据被篡改");
                    return;
                }
                logger.info(paymentRequestBean.getNo_order() + "订单处于付款处理中");
                detail.setPaymentStatus("P");
                detail.setPaymentMsg(paymentResponseBean.getRet_msg());
                detail.setPaymentCode(paymentResponseBean.getRet_code());
                QueryPaymentQueue.set(detail);
                // 已生成连连支付单，付款处理中（交易成功，不是指付款成功，是指跟连连流程正常），商户可以在这里处理自已的业务逻辑（或者不处理，在异步回调里处理逻辑）,最终的付款状态由异步通知回调告知
            } else if (paymentResponseBean.getRet_code().equals("4002")
                    || paymentResponseBean.getRet_code().equals("4004")) {
                // 当调用付款申请接口返回4002，4003，4004,会同时返回验证码，用于确认付款接口
                // 对于疑似重复订单，需先人工审核这笔订单是否正常的付款请求，而不是系统产生的重复订单，确认后再调用确认付款接口或者在连连商户站后台操作疑似订单，api不调用确认付款接口
                // 对于疑似重复订单，也可不做处理，
                // TODO
                detail.setPaymentStatus("P");
                detail.setPaymentMsg(paymentResponseBean.getRet_msg());
                detail.setPaymentCode(paymentResponseBean.getRet_code());
                QueryPaymentQueue.set(detail);
            } else if (RetCodeEnum.isNeedQuery(paymentResponseBean.getRet_code())) {
                // 出现1002，2005，4006，4007，4009，9999这6个返回码时（或者对除了0000之后的code都查询一遍查询接口）调用付款结果查询接口，明确订单状态，不能私自设置订单为失败状态，以免造成这笔订单在连连付款成功了，而商户设置为失败
                // 第一次测试对接时，返回{"ret_code":"4007","ret_msg":"敏感信息解密异常"},可能原因报文加密用的公钥改动了,demo中的公钥是连连公钥，商户生成的公钥用于上传连连商户站用于连连验签，生成的私钥用于加签
                detail.setPaymentStatus("P");
                detail.setPaymentMsg(paymentResponseBean.getRet_msg());
                detail.setPaymentCode(paymentResponseBean.getRet_code());
                QueryPaymentQueue.set(detail);
            } else {
                // 返回其他code时，可将订单置为失败
                // TODO
                logger.info(paymentRequestBean.getNo_order() + "订单失败");
                detail.setPaymentStatus("F");
                detail.setPaymentMsg(paymentResponseBean.getRet_msg());
                detail.setPaymentCode(paymentResponseBean.getRet_code());
            }
        }
        grantDetailMapper.updateGrantDetailByPayment(detail);
    }
    

    
    
    

    public int query(GrantDetailVo detail){
        if(!"P".equals(detail.getPaymentStatus())){
            //如果支付结果已经有了最终状态或者是线下支付，不发往第三方支付查询
            return 0;
        }

        QueryPaymentRequestBean queryRequestBean = new QueryPaymentRequestBean();
        queryRequestBean.setNo_order(detail.getId());
        queryRequestBean.setOid_partner(OID_PARTNER);
        queryRequestBean.setApi_version(API_VERSION);
        queryRequestBean.setSign_type(SIGN_TYPE);
        queryRequestBean.setSign(SignUtil.genRSASign(JSON.parseObject(JSON.toJSONString(queryRequestBean)),BUSINESS_PRIVATE_KEY));

        logger.info("sign str"+SignUtil.genRSASign(JSON.parseObject(JSON.toJSONString(queryRequestBean)),BUSINESS_PRIVATE_KEY));

        JSONObject json = JSON.parseObject(JSON.toJSONString(queryRequestBean));
        logger.info("实时付款查询请求报文：" + json);

        String queryResult = HttpUtil.doPost("https://instantpay.lianlianpay.com/paymentapi/queryPayment.htm", json,
                "UTF-8");
        System.out.print("实时付款查询接口返回响应报文：" + queryResult);
        logger.info("实时付款查询接口响应报文：" + queryResult);
        if (StringUtils.isEmpty(queryResult)) {
            // 可抛异常，查看原因
            logger.error("实时付款查询接口响应异常");
            return 1;
        }
        QueryPaymentResponseBean queryPaymentResponseBean = JSONObject.parseObject(queryResult,
                QueryPaymentResponseBean.class);

        // 先对结果验签
        boolean signCheck = TraderRSAUtil.checksign(PUBLIC_KEY_ONLINE,
                SignUtil.genSignData(JSONObject.parseObject(queryResult)), queryPaymentResponseBean.getSign());
        if (!signCheck) {
            // 传送数据被篡改，可抛出异常，再人为介入检查原因
            logger.error("返回结果验签异常,可能数据被篡改");
            return 1;
        }
        if (queryPaymentResponseBean.getRet_code().equals("0000")) {
            PaymentStatusEnum paymentStatusEnum = PaymentStatusEnum
                    .getPaymentStatusEnumByValue(queryPaymentResponseBean.getResult_pay());
            // TODO商户根据订单状态处理自已的业务逻辑
            switch (paymentStatusEnum) {
                case PAYMENT_APPLY:
                    // 付款申请，这种情况一般不会发生，如出现，请直接找连连技术处理
                    logger.info(detail.getId()+"请直接找连连技术处理");
                    detail.setPaymentStatus("F");
                    detail.setPaymentMsg(queryPaymentResponseBean.getRet_msg());
                    detail.setPaymentCode(queryPaymentResponseBean.getRet_code());
                    break;
                case PAYMENT_CHECK:
                    // 复核状态 TODO
                    // 返回4002，4003，4004时，订单会处于复核状态，这时还未创建连连支付单，没提交到银行处理，如需对该订单继续处理，需商户先人工审核这笔订单是否是正常的付款请求，没问题后再调用确认付款接口
                    // 如果对于复核状态的订单不做处理，可当做失败订单
                    logger.info(detail.getId()+"PAYMENT_CHECK");
                    detail.setPaymentStatus("F");
                    detail.setPaymentMsg(queryPaymentResponseBean.getRet_msg());
                    detail.setPaymentCode(queryPaymentResponseBean.getRet_code());
                    break;
                case PAYMENT_SUCCESS:
                    // 成功 TODO
                    logger.info(detail.getId()+"PAYMENT_SUCCESS");
                    detail.setPaymentStatus("S");
                    detail.setPaymentMsg(queryPaymentResponseBean.getRet_msg());
                    detail.setPaymentCode(queryPaymentResponseBean.getRet_code());
                    break;
                case PAYMENT_FAILURE:
                    // 失败 TODO
                    logger.info(detail.getId()+"PAYMENT_FAILURE");
                    detail.setPaymentStatus("F");
                    detail.setPaymentMsg(queryPaymentResponseBean.getRet_msg());
                    detail.setPaymentCode(queryPaymentResponseBean.getRet_code());
                    break;
                case PAYMENT_DEALING:
                    // 处理中 TODO
                    logger.info(detail.getId()+"PAYMENT_DEALING");
                    return 1;
                case PAYMENT_RETURN:
                    // 退款 TODO
                    // 可当做失败（退款情况
                    // 极小概率下会发生，个别银行处理机制是先扣款后打款给用户时再检验卡号信息是否正常，异常时会退款到连连商户账上）
                    logger.info(detail.getId()+"PAYMENT_RETURN");
                    detail.setPaymentStatus("F");
                    detail.setPaymentMsg(queryPaymentResponseBean.getRet_msg());
                    detail.setPaymentCode(queryPaymentResponseBean.getRet_code());
                    break;
                case PAYMENT_CLOSED:
                    // 关闭 TODO 可当做失败 ，对于复核状态的订单不做处理会将订单关闭
                    logger.info(detail.getId()+"PAYMENT_CLOSED");
                    detail.setPaymentStatus("F");
                    detail.setPaymentMsg(queryPaymentResponseBean.getRet_msg());
                    detail.setPaymentCode(queryPaymentResponseBean.getRet_code());
                    break;
                default:
                    logger.info(detail.getId()+"NON STATE");
                    detail.setPaymentStatus("F");
                    detail.setPaymentMsg(queryPaymentResponseBean.getRet_msg());
                    detail.setPaymentCode(queryPaymentResponseBean.getRet_code());
                    break;
            }
            grantDetailMapper.updateGrantDetailByPayment(detail);
            return 0;
        } else if (queryPaymentResponseBean.getRet_code().equals("8901")) {
            // 订单不存在，这种情况可以用原单号付款，最好不要换单号，如换单号，在连连商户站确认下改订单是否存在，避免系统并发时返回8901，实际有一笔订单
            logger.info("订单不存在");
            return 1;
        } else {
            // 查询异常（极端情况下才发生,对于这种情况，可人工介入查询，在连连商户站查询或者联系连连客服，查询订单状态）
            logger.error("查询异常");
            return 1;
        }
    }
    
}
